<!DOCTYPE html>
<html lang="zh-Hans">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.4.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"example.com","root":"/","scheme":"Mist","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="原文链接  李工翻译，转载请注明出处 加密猫游戏很好的证明了区块链除了简单金融交易以外的用途 我希望我们在未来能看到更多跟加密猫一样的区块链技术在游戏领域的创新应用。所以我希望能写一个关于加密猫代码的快速攻略，用来展示这个游戏是怎么被实现的。 这篇文章是写给开发者的，但这不是一个介绍Solidity的新手教程，我尝试包含了参考文档的链接使文章尽可能适用于所有层次的开发者。 让我们来一探究竟…">
<meta property="og:type" content="article">
<meta property="og:title" content="如何在以太网上创建你自己的加密猫游戏">
<meta property="og:url" content="http://example.com/2021/09/29/chuang-jian-jia-mi-mao/index.html">
<meta property="og:site_name" content="尼奥的乱码">
<meta property="og:description" content="原文链接  李工翻译，转载请注明出处 加密猫游戏很好的证明了区块链除了简单金融交易以外的用途 我希望我们在未来能看到更多跟加密猫一样的区块链技术在游戏领域的创新应用。所以我希望能写一个关于加密猫代码的快速攻略，用来展示这个游戏是怎么被实现的。 这篇文章是写给开发者的，但这不是一个介绍Solidity的新手教程，我尝试包含了参考文档的链接使文章尽可能适用于所有层次的开发者。 让我们来一探究竟…">
<meta property="og:locale">
<meta property="og:image" content="http://example.com/2021/09/29/chuang-jian-jia-mi-mao/1_b0GUOvwNgGnnJxu9Pyzibg.png">
<meta property="article:published_time" content="2021-09-29T01:50:51.708Z">
<meta property="article:modified_time" content="2021-09-29T01:50:51.708Z">
<meta property="article:author" content="李工">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://example.com/2021/09/29/chuang-jian-jia-mi-mao/1_b0GUOvwNgGnnJxu9Pyzibg.png">

<link rel="canonical" href="http://example.com/2021/09/29/chuang-jian-jia-mi-mao/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-Hans'
  };
</script>

  <title>如何在以太网上创建你自己的加密猫游戏 | 尼奥的乱码</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="Toggle navigation bar">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">尼奥的乱码</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>Home</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>Archives</a>

  </li>
        <li class="menu-item menu-item-首页">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-编程">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>编程</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-Hans">
    <link itemprop="mainEntityOfPage" href="http://example.com/2021/09/29/chuang-jian-jia-mi-mao/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="李工">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="尼奥的乱码">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          如何在以太网上创建你自己的加密猫游戏
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">Posted on</span>

              <time title="Created: 2021-09-29 09:50:51" itemprop="dateCreated datePublished" datetime="2021-09-29T09:50:51+08:00">2021-09-29</time>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <p><a target="_blank" rel="noopener" href="https://medium.com/loom-network/how-to-code-your-own-cryptokitties-style-game-on-ethereum-7c8ac86a4eb3">原文链接</a> </p>
<p>李工翻译，转载请注明出处</p>
<p>加密猫游戏很好的证明了区块链除了简单金融交易以外的用途</p>
<p>我希望我们在未来能看到更多跟加密猫一样的区块链技术在游戏领域的创新应用。所以我希望能写一个关于加密猫代码的快速攻略，用来展示这个游戏是怎么被实现的。</p>
<p>这篇文章是写给开发者的，但这不是一个介绍Solidity的新手教程，我尝试包含了参考文档的链接使文章尽可能适用于所有层次的开发者。</p>
<p>让我们来一探究竟…</p>
<span id="more"></span>

<h2 id="加密猫源代码"><a href="#加密猫源代码" class="headerlink" title="加密猫源代码"></a>加密猫源代码</h2><p>几乎所有的加密猫游戏代码都是开源的，所以搞懂加密猫是怎么工作的最好办法就是研读它的源代码。</p>
<p>总共有大约2000行左右的代码，所以在这篇文章里，我将只过一遍我觉得非常重要的部分。同时这里也有一份加密猫的所有智能合约代码的拷贝如果你想通过自己来阅读代码。</p>
<p><a target="_blank" rel="noopener" href="https://ethfiddle.com/09YbyJRfiI">加密猫源代码 EthFiddle</a></p>
<h2 id="顶层总览："><a href="#顶层总览：" class="headerlink" title="顶层总览："></a>顶层总览：</h2><p>如果你不是很熟悉什么是加密猫，那么我会告诉你加密猫其实是一个关于购买，出售以及繁殖数字猫咪的游戏。每只猫咪拥有一个唯一的外观（由它的基因所决定），当你尝试繁殖两只猫咪，它们的基因会以一种独特的方式结合在一起产生出新的后代。然后你可以出售或者继续繁殖这些后代品种。</p>
<p>加密猫的代码被分割成了若干小型的子合约用来分类，只让相关的代码绑定在一起，而不是形成一个巨大的文件包含了所有东西。</p>
<p>子合约从最主要的猫咪合约继承而来，它看上去像这个样子：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">contract KittyAccessControl</span><br><span class="line">contract KittyBase is KittyAccessControl</span><br><span class="line">contract KittyOwnership is KittyBase, ERC721</span><br><span class="line">contract KittyBreeding is KittyOwnership</span><br><span class="line">contract KittyAuction is KittyBreeding</span><br><span class="line">contract KittyMinting is KittyAuction</span><br><span class="line">contract KittyCore is KittyMinting</span><br></pre></td></tr></table></figure>

<p>由此可见 KittyCore 是应用指向的终极合约地址，同时它继承了前面合约的所有数据跟方法（类似于类型继承派生）。</p>
<p>让我们依次的过一遍这些合约：</p>
<hr>
<h3 id="1-KittyAccessControl-猫咪访问权限控制：谁控制这些合约？合约执行的权限。"><a href="#1-KittyAccessControl-猫咪访问权限控制：谁控制这些合约？合约执行的权限。" class="headerlink" title="1. KittyAccessControl 猫咪访问权限控制：谁控制这些合约？合约执行的权限。"></a>1. KittyAccessControl 猫咪访问权限控制：谁控制这些合约？合约执行的权限。</h3><p><em>该合约管理着多个地址跟约束条件，只为特定的角色提供操作权限，比如CEO，CFO，COO。</em></p>
<p>这个合约只是用来管理合约，而与游戏的机制没有一点关系。它只是提供了一些‘setter’设置方法给CEO，COO和CFO，只是一些以太坊地址，拥有着特殊的所有权并且支配着特定的合同功能。</p>
<p>KittyAccessControl定义了一些函数修改器比如onlyCEO（一个只有CEO能执行的函数），并且增加了一些方法来暂停/停止暂停 合同跟资金：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">modifier onlyCLevel() &#123;</span><br><span class="line">    require(</span><br><span class="line">        msg.sender == cooAddress ||</span><br><span class="line">        msg.sender == ceoAddress ||</span><br><span class="line">        msg.sender == cfoAddress</span><br><span class="line">    );</span><br><span class="line">    _;</span><br><span class="line">&#125;</span><br><span class="line">//...some other stuff</span><br><span class="line">// Only the CEO, COO, and CFO can execute this function:</span><br><span class="line">function pause() external onlyCLevel whenNotPaused &#123;</span><br><span class="line">    paused = true;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>pause()方法被加入的原因很可能是因为开发人员预测在系统发生了不可预料的bug的时候，可以暂停系统来进行修复和更新。但正如我的同事卢克指出的一样，事实上这可能会让开发人员拥有完全冻结合约的权利（中心化操作），然后将导致没有人能够转移，出售，或者繁殖他们的猫咪！有趣的是，因为大多数人认为DApp是完全去中心化的因为它们是运行在以太坊上的。</p>
<p>继续前进…</p>
<h3 id="2-KittyBase-猫咪Base：猫咪的基类，到底猫咪是个啥东西？"><a href="#2-KittyBase-猫咪Base：猫咪的基类，到底猫咪是个啥东西？" class="headerlink" title="2. KittyBase 猫咪Base：猫咪的基类，到底猫咪是个啥东西？"></a>2. KittyBase 猫咪Base：猫咪的基类，到底猫咪是个啥东西？</h3><p><em>这一部分我们定义了最基础的代码来共享整个核心功能。这包括我们的主数据存储，常量以及数据类型，以及包括用来管理这些数据的内部函数</em></p>
<p>KittyBase 定义了这个游戏的大量的核心数据。首先，它定义了一个猫咪结构体：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">struct Kitty &#123;</span><br><span class="line">    uint256 genes;</span><br><span class="line">    uint64 birthTime;</span><br><span class="line">    uint64 cooldownEndBlock;</span><br><span class="line">    uint32 matronId;</span><br><span class="line">    uint32 sireId;</span><br><span class="line">    uint32 siringWithId;</span><br><span class="line">    uint16 cooldownIndex;</span><br><span class="line">    uint16 generation;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>所以我猜测一只猫咪其实就是一大堆无符号整形数…</p>
<p>来细看每一个数据：</p>
<ul>
<li>genes 基因数： 一个256位整形用来表示猫咪的基因代码。这是核心数据用来决定这只猫咪的外形。</li>
<li>birthTime 出生时间： 一个区块的时间戳记录这只猫诞生的时间。</li>
<li>cooldownEndBlock 冷却结束： 一只猫能够再次参与繁殖的最小时间戳。</li>
<li>matronId &amp; sireId 父母ID： 分别表示这只猫咪的父母的ID。</li>
<li>siringWithId 怀的谁的：如果一直猫怀孕了，这里记录了配偶的的ID，否则为零。</li>
<li>cooldownIndex 冷却索引：这只猫的当前冷却时间（当一只猫咪交配繁殖以后到下一次能够繁殖所需要等待的时间）</li>
<li>generation 世代：表示这只猫是第几代。第一只由合同创造的猫的generation值为0；新生猫咪的世代值取父母世代最大值，加1。</li>
</ul>
<p>需要注意的是在加密猫里，猫咪都是无性的，任意两只猫被允许参与繁殖 —— 因此加密猫咪都是没有性别的。</p>
<p>KittyBase合约类型接着定义了一个猫咪合约类型的数据结构：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Kitty[] kitties;</span><br></pre></td></tr></table></figure>

<p>这个数组保持了现存的所有猫咪的数据，所以它有点像是主要的猫咪数据库。无论何时，当一只新的猫咪创建后，它会被加入到这个数组中来，数组的索引将成为这只猫的ID，比如创世猫拥的ID为1：</p>
<img src="/2021/09/29/chuang-jian-jia-mi-mao/1_b0GUOvwNgGnnJxu9Pyzibg.png" class="">

<p>这个合约同样包括了一组映射，从猫咪的ID到猫咪主人的地址，用来跟踪猫咪的主人信息：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">// 猫咪索引到所有者</span><br><span class="line">mapping (uint256 =&gt; address) public kittyIndexToOwner;</span><br></pre></td></tr></table></figure>

<p>同样合约定义了一些其它的映射，但因为本文章长度有限，在这里就不赘述了。</p>
<p>无论何时，当一只猫咪被从一个人转移到另一个人的时候，kittyIndexToOwner会被更新来反应它新的主人：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// @dev Assigns ownership of a specific Kitty to an address.</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_transfer</span>(<span class="params">address _from, address _to, uint256 _tokenId</span>) <span class="title">internal</span> </span>&#123;</span><br><span class="line">    <span class="comment">// Since the number of kittens is capped to 2^32 we can&#x27;t overflow this</span></span><br><span class="line">    ownershipTokenCount[_to]++;</span><br><span class="line">    <span class="comment">// transfer ownership</span></span><br><span class="line">    kittyIndexToOwner[_tokenId] = _to;</span><br><span class="line">    <span class="comment">// When creating new kittens _from is 0x0, but we can&#x27;t account that address.</span></span><br><span class="line">    <span class="keyword">if</span> (_from != address(<span class="number">0</span>)) &#123;</span><br><span class="line">        ownershipTokenCount[_from]--;</span><br><span class="line">        <span class="comment">// once the kitten is transferred also clear sire allowances</span></span><br><span class="line">        <span class="keyword">delete</span> sireAllowedToAddress[_tokenId];</span><br><span class="line">        <span class="comment">// clear any previously approved ownership exchange</span></span><br><span class="line">        <span class="keyword">delete</span> kittyIndexToApproved[_tokenId];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// Emit the transfer event.</span></span><br><span class="line">    Transfer(_from, _to, _tokenId);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p><em>转让猫咪的所有权将设置kittyIndexToOwner，将猫咪的ID设置为接收者的地址。</em></p>
<p>现在让我们来看一下当一只猫咪被创造的时候会发生什么：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">_createKitty</span>(<span class="params"></span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 _matronId,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 _sireId,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 _generation,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 _genes,</span></span></span><br><span class="line"><span class="params"><span class="function">    address _owner</span></span></span><br><span class="line"><span class="params"><span class="function"></span>)</span></span><br><span class="line"><span class="function"><span class="title">internal</span></span></span><br><span class="line"><span class="function"><span class="title">returns</span>(<span class="params">uint</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// These requires are not strictly necessary, our calling code should make</span></span><br><span class="line">    <span class="comment">// sure that these conditions are never broken. However! _createKitty() is already</span></span><br><span class="line">    <span class="comment">// an expensive call (for storage), and it doesn&#x27;t hurt to be especially careful</span></span><br><span class="line">    <span class="comment">// to ensure our data structures are always valid.</span></span><br><span class="line">    <span class="built_in">require</span>(_matronId == uint256(uint32(_matronId)));</span><br><span class="line">    <span class="built_in">require</span>(_sireId == uint256(uint32(_sireId)));</span><br><span class="line">    <span class="built_in">require</span>(_generation == uint256(uint16(_generation)));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// New kitty starts with the same cooldown as parent gen/2</span></span><br><span class="line">    uint16 cooldownIndex = uint16(_generation / <span class="number">2</span>);</span><br><span class="line">    <span class="keyword">if</span> (cooldownIndex &gt; <span class="number">13</span>) &#123;</span><br><span class="line">        cooldownIndex = <span class="number">13</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    Kitty memory _kitty = Kitty(&#123;</span><br><span class="line">        <span class="attr">genes</span>: _genes,</span><br><span class="line">        <span class="attr">birthTime</span>: uint64(now),</span><br><span class="line">        <span class="attr">cooldownEndBlock</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">matronId</span>: uint32(_matronId),</span><br><span class="line">        <span class="attr">sireId</span>: uint32(_sireId),</span><br><span class="line">        <span class="attr">siringWithId</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">cooldownIndex</span>: cooldownIndex,</span><br><span class="line">        <span class="attr">generation</span>: uint16(_generation)</span><br><span class="line">    &#125;);</span><br><span class="line">    uint256 newKittenId = kitties.push(_kitty) - <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// It&#x27;s probably never going to happen, 4 billion cats is A LOT, but</span></span><br><span class="line">    <span class="comment">// let&#x27;s just be 100% sure we never let this happen.</span></span><br><span class="line">    <span class="built_in">require</span>(newKittenId == uint256(uint32(newKittenId)));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// emit the birth event</span></span><br><span class="line">    Birth(</span><br><span class="line">        _owner,</span><br><span class="line">        newKittenId,</span><br><span class="line">        uint256(_kitty.matronId),</span><br><span class="line">        uint256(_kitty.sireId),</span><br><span class="line">        _kitty.genes</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="comment">// This will assign ownership, and also emit the Transfer event as</span></span><br><span class="line">    <span class="comment">// per ERC721 draft</span></span><br><span class="line">    _transfer(<span class="number">0</span>, _owner, newKittenId);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> newKittenId;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>所以这个方法传递了父亲跟母亲的ID，这只猫的世代编号，256位基因密码，以及拥有着的地址。接着创造了这只猫，将这只猫的数据推送到主猫咪数组，接着调用了_transfer()方法将它指派给它的新拥有着。</p>
<p>==很酷吧 - 所以现在我们明白了加密猫游戏如何将一只猫咪定义成一个数据类型，怎么将所有猫咪存储在区块链上，并且如何追踪谁拥有这些猫咪。==</p>
<h3 id="3-KittyOwnership合约-猫咪即代币"><a href="#3-KittyOwnership合约-猫咪即代币" class="headerlink" title="3. KittyOwnership合约: 猫咪即代币"></a>3. KittyOwnership合约: 猫咪即代币</h3><p><em>这个合约为基本的不可互换的代币交易提供了方法，符合ERC-721代币标准草案</em></p>
<p>加密猫符合ERC721代币标准，一个==不可互换==的代币类型使它自己能更好的追踪数字收藏品的所有权，就像数字卡牌游戏或者MMORPG里的稀有物品。</p>
<p>注意==可互换性==: 以太是可互换的，因为任意5ETH跟其它任意5ETH是一样的。但不可互换代币如以太猫，不是每一只猫都是平等的，所以它们互相之间都是不可替换的。</p>
<p>你能看到从它的合约定义里面，KittyOwnership是从ERC721合约继承下来的：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">contract KittyOwnership is KittyBase, ERC721 &#123;</span><br></pre></td></tr></table></figure>
<p>并且所有ERC721代币遵循同样的标准规范，所以KittyOwnership合约实现了如下方法：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens</span></span><br><span class="line"><span class="comment">/// @author Dieter Shirley &lt;dete@axiomzen.co&gt; (https://github.com/dete)</span></span><br><span class="line">contract ERC721 &#123;</span><br><span class="line">    <span class="comment">// Required methods</span></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">totalSupply</span>(<span class="params"></span>) <span class="title">public</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">uint256 total</span>)</span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">balanceOf</span>(<span class="params">address _owner</span>) <span class="title">public</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">uint256 balance</span>)</span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">ownerOf</span>(<span class="params">uint256 _tokenId</span>) <span class="title">external</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">address owner</span>)</span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">approve</span>(<span class="params">address _to, uint256 _tokenId</span>) <span class="title">external</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">transfer</span>(<span class="params">address _to, uint256 _tokenId</span>) <span class="title">external</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">transferFrom</span>(<span class="params">address _from, address _to, uint256 _tokenId</span>) <span class="title">external</span></span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Events</span></span><br><span class="line">    event Transfer(address <span class="keyword">from</span>, address to, uint256 tokenId);</span><br><span class="line">    event Approval(address owner, address approved, uint256 tokenId);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Optional</span></span><br><span class="line">    <span class="comment">// function name() public view returns (string name);</span></span><br><span class="line">    <span class="comment">// function symbol() public view returns (string symbol);</span></span><br><span class="line">    <span class="comment">// function tokensOfOwner(address _owner) external view returns (uint256[] tokenIds);</span></span><br><span class="line">    <span class="comment">// function tokenMetadata(uint256 _tokenId, string _preferredTransport) public view returns (string infoUrl);</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165)</span></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">supportsInterface</span>(<span class="params">bytes4 _interfaceID</span>) <span class="title">external</span> <span class="title">view</span> <span class="title">returns</span> (<span class="params">bool</span>)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>因为所有的方法都是public的，这提供了一种标准的方式给用户来与加密猫代币打交道，就像它们操作其它符合ERC721标准的代币。你能转移你的代币到其它用户通过直接在以太坊的区块链上操作加密猫的合约而不需要通过它们的web界面，这就意味这你真正拥有你的猫咪（除非CEO暂停这些合同）。</p>
<p>这里不一一探讨所有方法的实现了，但你可以直接在EthFiddle上搜索KittyOwnership。</p>
<hr>
<h3 id="中场休息：想创建一个你自己的以太坊游戏？"><a href="#中场休息：想创建一个你自己的以太坊游戏？" class="headerlink" title="中场休息：想创建一个你自己的以太坊游戏？"></a>中场休息：想创建一个你自己的以太坊游戏？</h3><p>这篇文章第一次发布的时候收到了大量的正面反馈，所以我们创建了<a target="_blank" rel="noopener" href="https://cryptozombies.io/">CryptoZombies</a>加密僵尸：一个教你在以太坊上创建自己的游戏的互动教程。它会叫你一步步的学习Solidity编码，并且创建你自己的以太坊游戏。如果你喜欢这篇文章，可以去查阅一下。</p>
<hr>
<h3 id="4-KittyBreeding合约：让猫咪变得污起来"><a href="#4-KittyBreeding合约：让猫咪变得污起来" class="headerlink" title="4. KittyBreeding合约：让猫咪变得污起来"></a>4. KittyBreeding合约：让猫咪变得污起来</h3><p><em>这个文件包括了让猫咪在一起繁殖的必要方法，包括为繁衍提供追踪，以及依赖一个外部的基因组合合约。</em></p>
<p>这个“外部的基因组合合约（基因科学）geneScience被存储在一个单独的合约中，这个合约不是开源的。</p>
<p>KittyBreeding合约为CEO包装了一个方法用来设置这个外部合约：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// @dev Update the address of the genetic contract, can only be called by the CEO.</span></span><br><span class="line"><span class="comment">/// @param _address An address of a GeneScience contract instance to be used from this point forward.</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">setGeneScienceAddress</span>(<span class="params">address _address</span>) <span class="title">external</span> <span class="title">onlyCEO</span> </span>&#123;</span><br><span class="line">    GeneScienceInterface candidateContract = GeneScienceInterface(_address);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// <span class="doctag">NOTE:</span> verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117</span></span><br><span class="line">    <span class="built_in">require</span>(candidateContract.isGeneScience());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Set the new contract address</span></span><br><span class="line">    geneScience = candidateContract;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>他们这样做让这个游戏变得不那么简单 - 如果你能读懂一只猫的DNA是如何决定的，也就会很容易知道哪些猫在一起繁殖可以产生牛逼的品种。</p>
<p>这个外部基因科学合约geneScience后面被用在giveBirth()函数用来决定新猫咪的DNA。</p>
<p>现在我们来看一看当两只猫在一起繁殖会发生什么：</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">/// @dev Internal utility function to initiate breeding, assumes that all breeding</span><br><span class="line">///  requirements have been checked.</span><br><span class="line">function _breedWith(uint256 _matronId, uint256 _sireId) internal &#123;</span><br><span class="line">    // Grab a reference to the Kitties from storage.</span><br><span class="line">    Kitty storage sire = kitties[_sireId];</span><br><span class="line">    Kitty storage matron = kitties[_matronId];</span><br><span class="line"></span><br><span class="line">    // Mark the matron as pregnant, keeping track of who the sire is.</span><br><span class="line">    matron.siringWithId = uint32(_sireId);</span><br><span class="line"></span><br><span class="line">    // Trigger the cooldown for both parents.</span><br><span class="line">    _triggerCooldown(sire);</span><br><span class="line">    _triggerCooldown(matron);</span><br><span class="line"></span><br><span class="line">    // Clear siring permission for both parents. This may not be strictly necessary</span><br><span class="line">    // but it&#x27;s likely to avoid confusion!</span><br><span class="line">    delete sireAllowedToAddress[_matronId];</span><br><span class="line">    delete sireAllowedToAddress[_sireId];</span><br><span class="line"></span><br><span class="line">    // Every time a kitty gets pregnant, counter is incremented.</span><br><span class="line">    pregnantKitties++;</span><br><span class="line"></span><br><span class="line">    // Emit the pregnancy event.</span><br><span class="line">    Pregnant(kittyIndexToOwner[_matronId], _matronId, _sireId, matron.cooldownEndBlock);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这个方法拿到了母亲跟父亲的ID，然后在主猫咪数组里查找到他们的实例，并将母亲的siringWithId设置成父亲的ID（当siringWithId为非零的时候，就知道这个母系猫已经怀孕）。</p>
<p>这个方法同样在父母猫上执行了triggerCooldown方法，用来使这两只猫无法在一段时间内继续繁殖，冷却一下。</p>
<p>接着，我们有一个giveBirth()方法用来创建一直新的猫咪：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// @notice Have a pregnant Kitty give birth!</span></span><br><span class="line"><span class="comment">/// @param _matronId A Kitty ready to give birth.</span></span><br><span class="line"><span class="comment">/// @return The Kitty ID of the new kitten.</span></span><br><span class="line"><span class="comment">/// @dev Looks at a given Kitty and, if pregnant and if the gestation period has passed,</span></span><br><span class="line"><span class="comment">///  combines the genes of the two parents to create a new kitten. The new Kitty is assigned</span></span><br><span class="line"><span class="comment">///  to the current owner of the matron. Upon successful completion, both the matron and the</span></span><br><span class="line"><span class="comment">///  new kitten will be ready to breed again. Note that anyone can call this function (if they</span></span><br><span class="line"><span class="comment">///  are willing to pay the gas!), but the new kitten always goes to the mother&#x27;s owner.</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">giveBirth</span>(<span class="params">uint256 _matronId</span>)</span></span><br><span class="line"><span class="function">    <span class="title">external</span></span></span><br><span class="line"><span class="function">    <span class="title">whenNotPaused</span></span></span><br><span class="line"><span class="function">    <span class="title">returns</span>(<span class="params">uint256</span>)</span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="comment">// Grab a reference to the matron in storage.</span></span><br><span class="line">    Kitty storage matron = kitties[_matronId];</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Check that the matron is a valid cat.</span></span><br><span class="line">    <span class="built_in">require</span>(matron.birthTime != <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Check that the matron is pregnant, and that its time has come!</span></span><br><span class="line">    <span class="built_in">require</span>(_isReadyToGiveBirth(matron));</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Grab a reference to the sire in storage.</span></span><br><span class="line">    uint256 sireId = matron.siringWithId;</span><br><span class="line">    Kitty storage sire = kitties[sireId];</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Determine the higher generation number of the two parents</span></span><br><span class="line">    uint16 parentGen = matron.generation;</span><br><span class="line">    <span class="keyword">if</span> (sire.generation &gt; matron.generation) &#123;</span><br><span class="line">        parentGen = sire.generation;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Call the sooper-sekret gene mixing operation.</span></span><br><span class="line">    uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Make the new kitten!</span></span><br><span class="line">    address owner = kittyIndexToOwner[_matronId];</span><br><span class="line">    uint256 kittenId = _createKitty(_matronId, matron.siringWithId, parentGen + <span class="number">1</span>, childGenes, owner);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Clear the reference to sire from the matron (REQUIRED! Having siringWithId</span></span><br><span class="line">    <span class="comment">// set is what marks a matron as being pregnant.)</span></span><br><span class="line">    <span class="keyword">delete</span> matron.siringWithId;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Every time a kitty gives birth counter is decremented.</span></span><br><span class="line">    pregnantKitties--;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Send the balance fee to the person who made birth happen.</span></span><br><span class="line">    msg.sender.send(autoBirthFee);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// return the new kitten&#x27;s ID</span></span><br><span class="line">    <span class="keyword">return</span> kittenId;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>代码内的注释信息已经解释的非常好了。基本上，这段代码首先执行了一些检测来判断母亲猫是否已经准备好生产。然后用geneScience.mixGenes()方法来决定孩子的基因，指定了新生猫咪的所有权为母亲猫的主人，最后调用在KittyBase里看到过的_createKitty()函数。<br>请注意geneScience.mixGenes()函数是一个黑盒不可见的函数，因为该协议（geneScience）是一个闭源协议。所以我们并不知道孩子猫的基因是如何决定的，但我们知道该函数是通过计算参数：母亲的基因，父亲的基因以及母亲的cooldownEndBlock来运转的。</p>
<h3 id="5-KittyAuctions-猫咪拍卖协议-购买，出售猫咪，让猫咪去接客，拉皮条"><a href="#5-KittyAuctions-猫咪拍卖协议-购买，出售猫咪，让猫咪去接客，拉皮条" class="headerlink" title="5. KittyAuctions 猫咪拍卖协议: 购买，出售猫咪，让猫咪去接客，拉皮条"></a>5. KittyAuctions 猫咪拍卖协议: 购买，出售猫咪，让猫咪去接客，拉皮条</h3><p><em>在这儿我们有一些public的方法用来拍卖或者竞标猫咪或者是配种服务。事实上拍卖功能由两种兄弟协议来掌控（一个是买卖，一个是配种），然而拍卖跟竞标主要是通过核心合约层面</em></p>
<p>根据开发介绍，他们将拍卖功能分割成sibling合约是由于“他们的逻辑优点复杂，有一些产生比较微妙的bug的风险。因此通过在它们各自的合约里，我们能够升级这些合约而不用扰乱用来追踪猫咪所有权的主要合约。”</p>
<p>所以这个KittyAuctions合约包含了如下的方法：</p>
<figure class="highlight plaintext"><figcaption><span>```setGeneScienceAddress()``` 一样只能被CEO调用，这些地址将被设置为外部合约。</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">*注意：“Siring”是指让你的猫去拉皮条，去卖，这样另外的用户就可以支付给你以太坊让你们的猫在一起干羞羞的事情。*</span><br><span class="line"></span><br><span class="line">这就意味着即使加密猫合同本身是不可变的，但CEO有灵活性去改变拍卖合同后面的地址，这将会改变拍卖的规则。再次强调，未必不是一件好事，因为有些时候开发人员需要去修正bug，但这一块是需要注意的地方。</span><br><span class="line"></span><br><span class="line">我将不会继续深入介绍拍卖跟竞标逻辑，但你能从EthFiddle上查阅这部分代码（搜索KittyAuctions）。</span><br><span class="line"></span><br><span class="line">### 6. KittyMinting 猫咪铸币： 初代猫咪工厂 </span><br><span class="line"></span><br><span class="line">*这是最后一块内容，包含了我们用来创建新的gen0猫咪。我们创造了5000只“推广”猫用来赠送（特别是当社区刚刚创建的时候），而其它所有的猫都只能被创建，然后通过一个指定的算法来设置一个初始价格然后就拉上去拍卖了。不管他们是如何创建的，他们都是被硬限制总数为50000只的初代猫。打那之后，一切由整个社区来继续繁殖，繁殖，繁殖！*</span><br><span class="line"></span><br><span class="line">赠送猫跟初代猫被硬编码在合约里：</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>uint256 public constant PROMO_CREATION_LIMIT = 5000;<br>uint256 public constant GEN0_CREATION_LIMIT = 45000;</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">接着这段代码是首席运营官COO用来创建赠送猫跟初代猫咪的：</span><br><span class="line">```javascript</span><br><span class="line">/// @dev we can create promo kittens, up to a limit. Only callable by COO</span><br><span class="line">/// @param _genes the encoded genes of the kitten to be created, any value is accepted</span><br><span class="line">/// @param _owner the future owner of the created kittens. Default to contract COO</span><br><span class="line">function createPromoKitty(uint256 _genes, address _owner) external onlyCOO &#123;</span><br><span class="line">    address kittyOwner = _owner;</span><br><span class="line">    if (kittyOwner == address(0)) &#123;</span><br><span class="line">         kittyOwner = cooAddress;</span><br><span class="line">    &#125;</span><br><span class="line">    require(promoCreatedCount &lt; PROMO_CREATION_LIMIT);</span><br><span class="line"></span><br><span class="line">    promoCreatedCount++;</span><br><span class="line">    _createKitty(0, 0, 0, _genes, kittyOwner);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/// @dev Creates a new gen0 kitty with the given genes and</span><br><span class="line">///  creates an auction for it.</span><br><span class="line">function createGen0Auction(uint256 _genes) external onlyCOO &#123;</span><br><span class="line">    require(gen0CreatedCount &lt; GEN0_CREATION_LIMIT);</span><br><span class="line"></span><br><span class="line">    uint256 kittyId = _createKitty(0, 0, 0, _genes, address(this));</span><br><span class="line">    _approve(kittyId, saleAuction);</span><br><span class="line"></span><br><span class="line">    saleAuction.createAuction(</span><br><span class="line">        kittyId,</span><br><span class="line">        _computeNextGen0Price(),</span><br><span class="line">        0,</span><br><span class="line">        GEN0_AUCTION_DURATION,</span><br><span class="line">        address(this)</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    gen0CreatedCount++;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过createPromoKitty()，看上去COO能够根据他自己的想法创建出新的猫咪，address参数表明COO能将这些猫咪送个他像送的人。我猜测这些人是早期beta测试人员，朋友以及家人，免费送给他们猫咪用来帮助推广产品，诸如此类。</p>
<p>但这同样意味着你的猫可能不如你想象的那么独一无二，因为他能暗中打印5000个相同的副本！<br>对于createGen0Auction(), COO同样提供了遗传代码给新的猫咪。但不同于将其分配给一个特定用户的地址，该方法创建了一个拍卖活动使得用户通过以太坊来竞拍得到这只猫咪。</p>
<h3 id="7-KittyCore-猫咪核心：最主要的合约"><a href="#7-KittyCore-猫咪核心：最主要的合约" class="headerlink" title="7. KittyCore 猫咪核心：最主要的合约"></a>7. KittyCore 猫咪核心：最主要的合约</h3><p>这是最主要的加密猫合约，是可以编译并且运行在以太坊区块链上的。这份合约将其它所有东西绑在一起。</p>
<p>因为继承结构的原因，它继承了前面所有合约，添加了一些少量的最终方法，比如这个通过猫咪的ID来获取一只猫咪的所有数据的函数。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// @notice Returns all the relevant information about a specific kitty.</span></span><br><span class="line"><span class="comment">/// @param _id The ID of the kitty of interest.</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">getKitty</span>(<span class="params">uint256 _id</span>)</span></span><br><span class="line"><span class="function">    <span class="title">external</span></span></span><br><span class="line"><span class="function">    <span class="title">view</span></span></span><br><span class="line"><span class="function">    <span class="title">returns</span> (<span class="params"></span></span></span><br><span class="line"><span class="params"><span class="function">    bool isGestating,</span></span></span><br><span class="line"><span class="params"><span class="function">    bool isReady,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 cooldownIndex,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 nextActionAt,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 siringWithId,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 birthTime,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 matronId,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 sireId,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 generation,</span></span></span><br><span class="line"><span class="params"><span class="function">    uint256 genes</span></span></span><br><span class="line"><span class="params"><span class="function"></span>) </span>&#123;</span><br><span class="line">    Kitty storage kit = kitties[_id];</span><br><span class="line"></span><br><span class="line">    <span class="comment">// if this variable is 0 then it&#x27;s not gestating</span></span><br><span class="line">    isGestating = (kit.siringWithId != <span class="number">0</span>);</span><br><span class="line">    isReady = (kit.cooldownEndBlock &lt;= block.number);</span><br><span class="line">    cooldownIndex = uint256(kit.cooldownIndex);</span><br><span class="line">    nextActionAt = uint256(kit.cooldownEndBlock);</span><br><span class="line">    siringWithId = uint256(kit.siringWithId);</span><br><span class="line">    birthTime = uint256(kit.birthTime);</span><br><span class="line">    matronId = uint256(kit.matronId);</span><br><span class="line">    sireId = uint256(kit.sireId);</span><br><span class="line">    generation = uint256(kit.generation);</span><br><span class="line">    genes = kit.genes;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>这是一个public的方法将从区块链上返回一只指定猫咪的所有数据。我猜想这可能是他们的web服务器用来做查询，从而显示猫咪在网站上的接口。</p>
<p>等等… 我并没有看到任何图像数据。到底是什么决定了一只猫咪的外观？</p>
<p>正如我们看到的代码一样，一只猫咪基本上是由一串256位无符号整形数来表示它的基因代码的。</p>
<p>Solidity合约代码中没有任何东西可以储存一只猫的图片，或者关于猫的描述。那到底什么来决定这个256位整形数到底是什么含义呢？其实基因代码是由加密猫的web服务器来进行翻译的。</p>
<p>所以尽管这真是一个聪明的区块链游戏的示范，但事实上它不是100%基于区块链技术的。如果他们的网站在未来离线了，除非有人备份了所有的图像，你将只能拥有一个毫无意义的256位整形数。</p>
<p>在合约代码里，我找到了一个合约名为ERC721Metadata，但它从未使用过。所以我猜测的是他们原本计划存储所有的数据在区块链上，但后来决定不这样搞了（存储大量数据在以太网上开销太大？）所以他们最后用web服务器来存储数据作为替代。</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>好了，总而言之，我们已经看了如下内容：</p>
<ul>
<li>猫咪是如何被定义成数据的</li>
<li>所有的存在的猫咪是如何被保存在单个智能合约里的，并且展示了如何来跟踪“谁拥有什么”</li>
<li>gen0初代猫是如何诞生的</li>
<li>猫咪如何在一起繁殖产生新的猫咪</li>
</ul>
<p>这只是一个顶层概述。如果你在寻找一个更加深入的教程关于如何创建你自己的游戏，你可能会对我们接下来几周发布的互动代码课程感兴趣。</p>
<p>更新：我们发布了这个课程。请前往：<br><a target="_blank" rel="noopener" href="https://cryptozombies.io/">https://cryptozombies.io</a></p>

    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2021/09/29/chuang-jian-jia-mi-huo-bi/" rel="prev" title="创建你自己的加密货币">
      <i class="fa fa-chevron-left"></i> 创建你自己的加密货币
    </a></div>
      <div class="post-nav-item">
    <a href="/2021/09/29/hex-editor/" rel="next" title="16进制编辑器">
      16进制编辑器 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          Table of Contents
        </li>
        <li class="sidebar-nav-overview">
          Overview
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8A%A0%E5%AF%86%E7%8C%AB%E6%BA%90%E4%BB%A3%E7%A0%81"><span class="nav-number">1.</span> <span class="nav-text">加密猫源代码</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E9%A1%B6%E5%B1%82%E6%80%BB%E8%A7%88%EF%BC%9A"><span class="nav-number">2.</span> <span class="nav-text">顶层总览：</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#1-KittyAccessControl-%E7%8C%AB%E5%92%AA%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90%E6%8E%A7%E5%88%B6%EF%BC%9A%E8%B0%81%E6%8E%A7%E5%88%B6%E8%BF%99%E4%BA%9B%E5%90%88%E7%BA%A6%EF%BC%9F%E5%90%88%E7%BA%A6%E6%89%A7%E8%A1%8C%E7%9A%84%E6%9D%83%E9%99%90%E3%80%82"><span class="nav-number">2.1.</span> <span class="nav-text">1. KittyAccessControl 猫咪访问权限控制：谁控制这些合约？合约执行的权限。</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#2-KittyBase-%E7%8C%AB%E5%92%AABase%EF%BC%9A%E7%8C%AB%E5%92%AA%E7%9A%84%E5%9F%BA%E7%B1%BB%EF%BC%8C%E5%88%B0%E5%BA%95%E7%8C%AB%E5%92%AA%E6%98%AF%E4%B8%AA%E5%95%A5%E4%B8%9C%E8%A5%BF%EF%BC%9F"><span class="nav-number">2.2.</span> <span class="nav-text">2. KittyBase 猫咪Base：猫咪的基类，到底猫咪是个啥东西？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-KittyOwnership%E5%90%88%E7%BA%A6-%E7%8C%AB%E5%92%AA%E5%8D%B3%E4%BB%A3%E5%B8%81"><span class="nav-number">2.3.</span> <span class="nav-text">3. KittyOwnership合约: 猫咪即代币</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E4%B8%AD%E5%9C%BA%E4%BC%91%E6%81%AF%EF%BC%9A%E6%83%B3%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E4%BD%A0%E8%87%AA%E5%B7%B1%E7%9A%84%E4%BB%A5%E5%A4%AA%E5%9D%8A%E6%B8%B8%E6%88%8F%EF%BC%9F"><span class="nav-number">2.4.</span> <span class="nav-text">中场休息：想创建一个你自己的以太坊游戏？</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-KittyBreeding%E5%90%88%E7%BA%A6%EF%BC%9A%E8%AE%A9%E7%8C%AB%E5%92%AA%E5%8F%98%E5%BE%97%E6%B1%A1%E8%B5%B7%E6%9D%A5"><span class="nav-number">2.5.</span> <span class="nav-text">4. KittyBreeding合约：让猫咪变得污起来</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#5-KittyAuctions-%E7%8C%AB%E5%92%AA%E6%8B%8D%E5%8D%96%E5%8D%8F%E8%AE%AE-%E8%B4%AD%E4%B9%B0%EF%BC%8C%E5%87%BA%E5%94%AE%E7%8C%AB%E5%92%AA%EF%BC%8C%E8%AE%A9%E7%8C%AB%E5%92%AA%E5%8E%BB%E6%8E%A5%E5%AE%A2%EF%BC%8C%E6%8B%89%E7%9A%AE%E6%9D%A1"><span class="nav-number">2.6.</span> <span class="nav-text">5. KittyAuctions 猫咪拍卖协议: 购买，出售猫咪，让猫咪去接客，拉皮条</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#7-KittyCore-%E7%8C%AB%E5%92%AA%E6%A0%B8%E5%BF%83%EF%BC%9A%E6%9C%80%E4%B8%BB%E8%A6%81%E7%9A%84%E5%90%88%E7%BA%A6"><span class="nav-number">2.7.</span> <span class="nav-text">7. KittyCore 猫咪核心：最主要的合约</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%80%BB%E7%BB%93"><span class="nav-number">2.8.</span> <span class="nav-text">总结</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">李工</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">4</span>
          <span class="site-state-item-name">posts</span>
        </a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2021</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">李工</span>
</div>
  <div class="powered-by">Powered by <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://mist.theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Mist</a>
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/muse.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

</body>
</html>
